﻿using System;
using BITS.PreCompiler.CSharp.Syntax;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace BITS.PreCompiler.CSharp.Tests.Syntax
{
    [TestClass]
    public class TestNamespace : TestBase
    {
        [TestMethod]
        public void Create_Namespace()
        {
            var @namespace = new Namespace(name: "MyNamespace");

            var expectet = Comparer.Create_Namespace();
            var actual = @namespace.ToString();

            Assert.AreEqual(expectet, actual);
            Console.WriteLine(actual);
        }

        [TestMethod]
        public void Create_Nested_Namespaces()
        {
            var @namespace = new Namespace(name: "MyNamespace")
            {
                new Namespace(name: "MySecondNamespace")
                {
                    new Class("MyClass"),
                },  
            };

            var expectet = Comparer.Create_Nested_Namespaces();
            var actual = @namespace.ToString();
            Assert.AreEqual(expectet, actual);
            Console.WriteLine(actual);
        }

        [TestMethod]
        public void Create_Namespace_Long()
        {
            var @namespace = new Namespace(name: "MyNamespace.A.B.C");

            var expectet = Comparer.Create_Namespace_Long();
            var actual = @namespace.ToString();

            Assert.AreEqual(expectet, actual);
            Console.WriteLine(actual);
        }

        [TestMethod]
        public void Create_Namespace_With_Usings()
        {
            var @namespace = new Namespace(name: "MyNamespace.A.B.C")
            {
                new Using(name: "A_Namespace"),

                @"using NewNameSpace;",
            };

            var expectet = Comparer.Create_Namespace_With_Usings();
            var actual = @namespace.ToString();

            Assert.AreEqual(expectet, actual);
            Console.WriteLine(actual);
        }

        [TestMethod]
        public void Create_Namespace_With_Many_Usings()
        {
            var @namespace = new Namespace(name: "MyNamespace.A.B.C")
            {
                new Using(name: "A"),
                new Using(name: "B"),
                new Using(name: "C"),
            };

            var expectet = Comparer.Create_Namespace_With_Many_Usings();
            var actual = @namespace.ToString();

            Assert.AreEqual(expectet, actual);
            Console.WriteLine(actual);
        }

        [TestMethod]
        public void Create_Namespace_With_Members()
        {
            var useNamespace = new Namespace(name: "MyNamespace.XX.X");

            var @namespace = new Namespace(name: "MyNamespace.A.B.C")
            {
                new Namespace(name: "InnerNamespace"),

                new Using(useNamespace),

                new Class("TypeA"),
            };

            var expectet = Comparer.Create_Namespace_With_Members();
            var actual = @namespace.ToString();

            Assert.AreEqual(expectet, actual);
            Console.WriteLine(actual);
        }

        [TestMethod]
        public void Create_Namespace_With_Class()
        {
            var typeA = new Class("TypeA");

            var @namespace = new Namespace(name: "MyNamespace.A.B.C")
            {
                @"private Class X {}",

                new Class("MyClass")
                {
                    @"public int TestPropertyA { get; set; }",
                
                    @"public string TestPropertyB { get; set; }",

                    new Property(@return: "NewClass", identifier: "PropertyC")
                        .WithAutoAccessors(),

                    new Property(@return: "NewClass", identifier: "PropertyD")
                    {
                        @"get { return new NewClass(); }",
                        @"set { return null; }",
                    },
                    
                    @"public int TestMethodA()
                    {
                        var x = 0;

                        return x;
                    }",

                    new Method(typeA, identifier: "MethodB")
                    {
                        @"int i = 0; string x;",

                        @"return null;",
                    },

                    new Class("InnerClassAA")
                    {
                        typeA,
                    },

                    typeA,
                },
            };

            //@namespace.Classes.Where(x => x.Identifier == "X");

            var expectet = Comparer.Create_Namespace_With_Class();
            var actual = @namespace.ToString();

            Assert.AreEqual(expectet, actual);
            Console.WriteLine(actual);
        }


        public static class Comparer
        {
            public static String Create_Namespace()
            {
                return
@"namespace MyNamespace
{
}";
            }

            public static String Create_Nested_Namespaces()
            {
                return
@"namespace MyNamespace
{
    namespace MySecondNamespace
    {
        public class MyClass
        {
        }
    }
}";
            }

            public static String Create_Namespace_Long()
            {
                return
@"namespace MyNamespace.A.B.C
{
}";
            }

            public static String Create_Namespace_With_Usings()
            {
                return
@"namespace MyNamespace.A.B.C
{
    using A_Namespace;
    using NewNameSpace;
}";
            }

            public static String Create_Namespace_With_Many_Usings()
            {
                return
@"namespace MyNamespace.A.B.C
{
    using A;
    using B;
    using C;
}";
            }

            public static String Create_Namespace_With_Members()
            {
                return
@"namespace MyNamespace.A.B.C
{
    using MyNamespace.XX.X;

    namespace InnerNamespace
    {
    }

    public class TypeA
    {
    }
}";
            }

            public static String Create_Namespace_With_Class()
            {
                return
@"namespace MyNamespace.A.B.C
{
    public class MyClass
    {
        public int TestPropertyA { get; set; }
        public string TestPropertyB { get; set; }
        private NewClass PropertyC { get; set; }

        private NewClass PropertyD
        {
            get
            {
                return new NewClass();
            }

            set
            {
                return null;
            }
        }

        public int TestMethodA()
        {
            var x = 0;

            return x;
        }

        private TypeA MethodB()
        {
            int i = 0; string x;
            return null;
        }

        public class InnerClassAA
        {
            public class TypeA
            {
            }
        }

        public class TypeA
        {
        }
    }
}";
            }
        }
    }
}
